
package com.jf.cloud.biz.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.jf.cloud.biz.config.MinioTemplate;
import com.jf.cloud.biz.config.OssConfig;
import com.jf.cloud.biz.constant.OssType;
import com.jf.cloud.biz.vo.OssVO;
import com.jf.cloud.common.response.ServerResponseEntity;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author zz
 * @date 2020/9/10
 */
@RequestMapping(value = "/ua/oss")
@RestController
@Tag(name = "文件管理")
public class OssController {

    private static final Logger log = LoggerFactory.getLogger(OssController.class);

    /**
     * 上传的文件夹(根据时间确定)
     */
    public static final String NORM_DAY_PATTERN = "yyyy/MM/dd";

    public static final String AGREE_ON = "://";

    /**
     * 上传文件要求的最小长度
     */
    public static final Integer MIN_LENGTH = 0;

    @Autowired
    private OssConfig ossConfig;
    @Autowired
    private OSS ossClient;
    @Autowired
    private MinioTemplate minioTemplate;


    @GetMapping(value = "/info")
    @Operation(summary = "token" , description = "获取文件上传需要的token")
    @Parameter(name = "fileNum", description = "需要获取token的文件数量")
    public ServerResponseEntity<OssVO> info(@RequestParam("fileNum") Integer fileNum) {
        OssVO ossVO = new OssVO();
        // 阿里文件上传
        if (Objects.equals(ossConfig.getOssType(), OssType.ALI.value())) {
            fillAliOssInfo(ossVO, fileNum);
        }
        // minio文件上传
        else if (Objects.equals(ossConfig.getOssType(), OssType.MINIO.value())) {
            fillMinIoInfo(ossVO, fileNum);
        }
//        //腾讯云cos文件上传
//        else if (Objects.equals(ossConfig.getOssType(), OssType.Q_CLOUD.value())) {
//            fillQcloudInfo(ossVO, fileNum);
//        }
        return ServerResponseEntity.success(ossVO);
    }

    private void fillAliOssInfo(OssVO ossVO, Integer fileNum) {
        loadOssVO(ossVO);
        String[] split = ossConfig.getEndpoint().split(AGREE_ON);
        // host的格式为 bucketname.endpoint
        String host = split[0] + AGREE_ON + ossConfig.getBucket() + StrUtil.DOT + split[1];
        try {
            long expireTime = 30 * 1000L;
            long expireEndTime = System.currentTimeMillis() + expireTime;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            // 20
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, MIN_LENGTH, ossConfig.getMaxLength() * 1024 * 1024L);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, ossVO.getDir());

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            ossVO.setAccessid(ossConfig.getAccessId());
            ossVO.setHost(host);
            ossVO.setSignature(postSignature);
            ossVO.setPolicy(encodedPolicy);
            ossVO.setExpire(30);
            // 文件名称
            List<OssVO> ossVOList = new ArrayList<>();
            for (int i = 0; i < fileNum; i++) {
                OssVO oss = loadOssVO(new OssVO());
                ossVOList.add(oss);
            }
            ossVO.setOssList(ossVOList);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    private void fillMinIoInfo(OssVO ossVo, Integer fileNum) {
        List<OssVO> ossVOList = new ArrayList<>();
        for (int i = 0; i < fileNum; i++) {
            OssVO oss = loadOssVO(new OssVO());
            String actionUrl = minioTemplate.getPresignedObjectUrl(oss.getDir() + oss.getFileName());
            oss.setActionUrl(actionUrl);
            ossVOList.add(oss);
        }
        ossVo.setOssList(ossVOList);
    }

//    private void fillQcloudInfo(OssVO ossVo, Integer fileNum) {
//        ArrayList<OssVO> ossVOList = new ArrayList<>();
//        for (int i = 0; i < fileNum; i++) {
//            OssVO oss = loadOssVO(new OssVO());
//            BasicCOSCredentials cred = new BasicCOSCredentials(ossConfig.getAccessId(), ossConfig.getAccessKeySecret());
//            Region region = new Region(ossConfig.getEndpoint());
//            ClientConfig clientConfig = new ClientConfig(region);
//            clientConfig.setHttpProtocol(HttpProtocol.https);
//            COSClient cosClient = new COSClient(cred, clientConfig);
//            Date expirationTime = new Date(System.currentTimeMillis() + 30 * 1000L);
//            URL url = cosClient.generatePresignedUrl(ossConfig.getBucket(), oss.getDir() + oss.getFileName(), expirationTime, HttpMethodName.PUT);
//            oss.setActionUrl(url.toString());
//            ossVOList.add(oss);
//            cosClient.shutdown();
//        }
//        ossVo.setOssList(ossVOList);
//    }

    private OssVO loadOssVO(OssVO ossVo) {
        String dir = DateUtil.format(new Date(), NORM_DAY_PATTERN) + "/";
        String fileName = IdUtil.simpleUUID();
        ossVo.setDir(dir);
        ossVo.setFileName(fileName);
        return ossVo;
    }

    @PostMapping("/upload_minio")
    @Operation(summary = "文件上传接口" , description = "上传文件，返回文件路径与域名")
    public ServerResponseEntity<OssVO> uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            return ServerResponseEntity.success();
        }
        OssVO oss = loadOssVO(new OssVO());
        minioTemplate.uploadMinio(file.getBytes(), oss.getDir() + oss.getFileName(), file.getContentType());
        return ServerResponseEntity.success(oss);
    }

    @PostMapping("/upload_oss")
    @Operation(summary = "文件上传接口" , description = "上传文件，返回文件路径与域名")
    public ServerResponseEntity<String> uploadOssFile(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return ServerResponseEntity.success();
        }


        String returnUrl = "";
        // 获取文件原名称
        String originalFilename = file.getOriginalFilename();
        // 获取文件类型
        log.info("文件"+file.getContentType());
        String fileType = file.getContentType().split("/")[1];
        // 新文件名称
        String newFileName = UUID.randomUUID().toString() + "."+fileType;
        // 构建日期路径, 例如：OSS目标文件夹/2020/10/31/文件名
//        String filePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
        // 文件上传的路径地址
        String fileUrl = "temp_word/" + newFileName;

        // 获取文件输入流
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        /**
         * 下面两行代码是重点坑：
         * 现在阿里云OSS 默认图片上传ContentType是image/jpeg
         * 也就是说，获取图片链接后，图片是下载链接，而并非在线浏览链接，
         * 因此，这里在上传的时候要解决ContentType的问题，将其改为image/jpg
         */
//        ObjectMetadata meta = new ObjectMetadata();
//        meta.setContentType("image/jpg");

        //文件上传至阿里云OSS
        ossClient.putObject(ossConfig.getBucket(), fileUrl, inputStream);
        /**
         * 注意：在实际项目中，文件上传成功后，数据库中存储文件地址
         */
        // 获取文件上传后的图片返回地址
        //oss-cn-hangzhou.aliyuncs.com
        returnUrl = "https://jingfengkeji.oss-cn-zhangjiakou.aliyuncs.com/" + fileUrl;
        return ServerResponseEntity.success(returnUrl);
    }
}
